using System;
using System.IO;

namespace csammisrun.OscarLib.Utility
{
  static class IconVerifier
  {
    /// <summary>
    /// Verifies that a user-chosen icon fits within the AOL requirements
    /// </summary>
    /// <param name="filename">The location of the image file</param>
    /// <returns><c>true</c> if the icon fits within parameters,
    /// <c>false</c> otherwise</returns>
    public static bool CheckIcon(string filename)
    {
      FileStream fs = null;
      try
      {
        FileInfo fi = new FileInfo(filename);
        fs = File.OpenRead(filename);
        byte[] fourbytes = new byte[4];
        fs.Read(fourbytes, 0, 4);

        if (fi.Extension.ToLower() == "ico")
        {
          // We have to let AOL figure out icons, since there
          // is most likely a 32x32 or a 48x48 image in the
          // icon somewhere, but it's more than a job to figure
          // that much out, and to potentially have to extract it...
          return true;
        }
        else if (fourbytes[0] == 'B' && fourbytes[1] == 'M')
        {
          return VerifyBitmap(fs);
        }
        else if (fourbytes[0] == 'G' && fourbytes[1] == 'I' &&
          fourbytes[2] == 'F' && fourbytes[3] == '8')
        {
          return VerifyGIF(fs);
        }
        else if (fourbytes[0] == 0xFF && fourbytes[1] == 0xD8 &&
          fourbytes[2] == 0xFF && fourbytes[2] == 0xE0)
        {
          return VerifyJFIF(fs);
        }
        else
          return false;
      }
      catch // Any exception at all
      {
        return false;
      }
      finally
      {
        if (fs != null)
          fs.Close();
      }
    }

    /// <summary>
    /// Verifies that a JPEG File Interchange Format image falls inside the
    /// AOL-required dimensions:  between 48x48 and 50x50
    /// </summary>
    /// <param name="fs">
    /// An opened <see cref="FileStream"/> two bytes into the JFIF.
    /// </param>
    /// <returns>
    /// <c>true</c> if the JFIF fits in the required dimensions,
    /// <c>false</c> otherwise.
    /// </returns>
    private static bool VerifyJFIF(FileStream fs)
    {
      // Scroll to the Start Frame 0 position in the image
      bool foundframe0 = false;
      while (!foundframe0 && fs.Position < fs.Length)
      {
        if (fs.ReadByte() == 0xFF && fs.ReadByte() == 0xC0)
          break;
      }
      if (fs.Position == fs.Length)
        return false;

      // Three skip bytes, then the next four are the width and height (in NBO format)
      byte[] size = new byte[7];
      if (fs.Read(size, 0, size.Length) != size.Length)
        return false;

      int index = 3;
      ushort height = Marshal.ByteArrayToUshort(size, ref index);
      ushort width  = Marshal.ByteArrayToUshort(size, ref index);
      return (width >= 48 && width <= 50) && (height >= 48 && height <= 50);
    }

    /// <summary>
    /// Verifies that a Graphics Interchange Format image falls inside the
    /// AOL-required dimensions:  between 48x48 and 50x50
    /// </summary>
    /// <param name="fs">
    /// An opened <see cref="FileStream"/> two bytes into the GIF.
    /// </param>
    /// <returns>
    /// <c>true</c> if the GIF fits in the required dimensions,
    /// <c>false</c> otherwise.
    /// </returns>
    private static bool VerifyGIF(FileStream fs)
    {
      // We don't care about the next 2 bytes...
      for (int i = 0; i < 2; i++)
        fs.ReadByte();

      // Then the next four are the width and height of the gif
      byte[] size = new byte[4];
      fs.Read(size, 0, size.Length);

      ushort width  = BitConverter.ToUInt16(size, 0);
      ushort height = BitConverter.ToUInt16(size, size.Length / 2);
      return (width >= 48 && width <= 50) && (height >= 48 && height <= 50);
    }

    /// <summary>
    /// Verifies that a Device-Independent Bitmap falls inside the
    /// AOL-required dimensions:  between 48x48 and 50x50
    /// </summary>
    /// <param name="fs">
    /// An opened <see cref="FileStream"/> two bytes into the bitmap.
    /// </param>
    /// <returns>
    /// <c>true</c> if the bitmap fits in the required dimensions,
    /// <c>false</c> otherwise.
    /// </returns>
    private static bool VerifyBitmap(FileStream fs)
    {
      // We don't care about the next 16 bytes...
      for (int i = 0; i < 16; i++)
        fs.ReadByte();

      // Then the next eight are the width and height of the bmp
      byte[] size = new byte[8];
      fs.Read(size, 0, size.Length);

      uint width =  BitConverter.ToUInt32(size, 0);
      uint height = BitConverter.ToUInt32(size, size.Length / 2);
      return (width >= 48 && width <= 50) && (height >= 48 && height <= 50);
    }
  }
}
